using System;
using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;
using ScrapySharp.Extensions;
using TripleA.Core.Interfaces;

namespace TripleA.Core.Extensions.Web
{
    public class GetHtmlElementStep<T> : StepBase<T>
        where T: IWebContext
    {
        public string ElementPath { get; set; }
        public string CssSelector { get; set; }
        public string ExpectedText { get; set; }
        public int? ExpectedCount { get; set; }
        public Predicate<IEnumerable<HtmlNode>> Assert { get; set; }

        public override void PreValidate(T context)
        {
            if (context.Response == null)
                throw new ApplicationException("Response is null");
        }

        public override void Execute(T context)
        {
            IEnumerable<HtmlNode> nodes;
            var doc = new HtmlDocument();

            doc.LoadHtml(context.Response.Content);

            if (!string.IsNullOrWhiteSpace(ElementPath))
            {
                // xpath selector
                var elements = doc.DocumentNode.SelectNodes(ElementPath);
                nodes = (elements == null) ? new HtmlNode[0] : elements.ToArray();
            }
            else
            {
                // css selector
                nodes = doc.DocumentNode.CssSelect(CssSelector);
            }
            
            if (Assert != null)
                Assert(nodes);

            if (ExpectedCount.HasValue)
            {
                if (nodes.Count() != ExpectedCount.Value)
                {
                    throw new ApplicationException(string.Format("Expected {0} elements, Actual {1}", 
                        ExpectedCount.Value, 
                        nodes.Count()));
                }
            }

            if (nodes.Count() == 0)
                return;

            if (!string.IsNullOrWhiteSpace(ExpectedText))
            {
                if (string.CompareOrdinal(nodes.ElementAt(0).InnerText, ExpectedText) != 0)
                    throw new ApplicationException(string.Format("Expected {0} text, Actual {1}", 
                        ExpectedText, nodes.ElementAt(0).InnerText));
            }
        }
    }
}